import { MemoryStore, SessionData } from "express-session";
import { ensureDirSync, readFileSync, writeFileSync } from 'fs-extra'
import { dirname, join } from "path";
import { DependencyContainer, injectable } from "tsyringe";
import { ROOT } from "./tokens";
import { EventEmitter } from 'events'
import { logger } from "./logger";
EventEmitter.setMaxListeners(10000)
@injectable()
export class LocalMemoryStore extends MemoryStore {
    private path: string;
    constructor(private injector: DependencyContainer) {
        super();
        const root = this.injector.resolve(ROOT)
        const path = join(root, 'data', 'logs', 'session.json')
        ensureDirSync(dirname(path))
        this.path = path;
    }
    private saveToJson(json: any) {
        logger.info(`write`)
        writeFileSync(this.path, JSON.stringify(json, null, 2))
    }
    sessions: any[] = [];
    private getFromJson(): { sid: string, data: SessionData }[] {
        if (this.sessions && this.sessions.length > 0) return this.sessions;
        try {
            return JSON.parse(readFileSync(this.path, 'utf-8'))
        } catch (e) {
            return []
        }
    }
    get(sid: string, callback: (err: any, session?: SessionData | null) => void): void {
        const data = this.getFromJson().find(it => it.sid === sid)
        if (data) {
            callback(null, data.data)
        } else {
            callback(null, null)
        }
    }
    set(sid: string, session: SessionData, callback?: (err?: any) => void): void {
        const list = this.getFromJson().filter(it => it.sid !== sid);
        const newSessions = [{ sid, data: session }, ...list]
        this.sessions = newSessions
        this.saveToJson(newSessions)
        callback(null)
    }
    destroy(sid: string, callback?: (err?: any) => void): void {
        const list = this.getFromJson().filter(it => it.sid !== sid);
        this.saveToJson([...list])
        callback(null)
    }
    all(callback: (err: any, obj?: { [sid: string]: SessionData } | null) => void): void {
        const list = this.getFromJson()
        const obj = list.map(it => ({ [it.sid]: it.data })).reduce((a, b) => ({ ...a, ...b }), {})
        callback(null, obj)
    }
    length(callback: (err: any, length?: number) => void): void {
        const list = this.getFromJson()
        callback(null, list.length)
    }
    clear(callback?: (err?: any) => void): void {
        this.saveToJson([])
        callback(null)
    }
    touch(sid: string, session: SessionData, callback?: () => void): void {
        const list = this.getFromJson().filter(it => it.sid !== sid);
        const newSessions = [{ sid, data: session }, ...list]
        this.sessions = newSessions
        this.saveToJson(newSessions)
        callback()
    }
}
